Repository navigation
fix: drop RegExp.exec, negation and test-helper false positives - #2
Merged
Revinand merged 4 commits intoNov 15, 2026
Merged
Conversation
Revinand
approved these changes
Nov 15, 2026
Revinand
deleted the
fix/false-positives-regexp-negation-test-helpers
branch
November 15, 2026 12:58
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three false positives found by scanning the modelcontextprotocol/servers reference servers in source mode.
Taint: RegExp.prototype.exec reported as command injection
The bare
execsink, meant forimport { exec } from "child_process", matched anyX.exec(...). In the filesystem server,WINDOWS_DRIVE_PREFIX.exec(path)andWINDOWS_UNC_ROOT.exec(path)were HIGH command injection. A JavaScript/TypeScript receiver now skips the sink only when it is a regex literal,new RegExp(...),RegExp(...), or a name the file binds only to one of these. A name assigned anything else, or shadowed by a parameter, loop variable or catch binding, keeps the sink.Behavioral: negation read at the wrong occurrence
negatedNearlooked for a negator before the first substring match of the word (strings.Cut), while the word itself was matched on word boundaries. "api" was looked up inside "rapid", and only the first occurrence of a word in a sentence was checked. The fetch server's description ("...you did not have internet access, ... this tool now grants you internet access") was reported asbehavioral.contradicted_networkat HIGH. Each whole-word occurrence is now judged at its own position, and a word that the same sentence both negates and uses plainly is not a denial. Other words of the category do not lift a denial: "never contacts the network or any web api" still denies the network.Source: a local function named
toolregistered as an MCP toolIn a tree that imports an MCP SDK, a receiver-less
tool(a, b, ...)call counted as a registration. The fetch server's test helpertool(bindir, "node", body)produced 16 tools namednode,npmandreader, which behavioral, taint and yara then reported as discovered but not analyzed. A receiver-less call that resolves to the project's own function and passes no function argument is no longer a registration. The call still counts when the calling file imports that name from a package, or when it passes an inline function or a function defined in the tree, the shape of a hand-rolled registry such astool("read_note", "...", async (args) => ...). Calls through a receiver (server.tool(...)) are unchanged.Results
Source scans of modelcontextprotocol/servers at e1dc4b1:
Behaviour changes
Fewer
taint.command_injectionfindings on regex.execcalls and fewerbehavioral.contradicted_*findings on descriptions that use the negated word plainly in the same sentence. Trees with a local function namedtool,promptorresourcereport fewer capabilities and so fewer coverage gaps.Notes
internal/conventionsfailed on master since 1c22b1d: two comments named the placeholder pathdocs/release-notes/TAG.mdand nothing linkeddocs/release-notes/v1.1.0.md. The last commit writes the placeholder as<TAG>and links the v1.1.0 notes from the README documentation list.